#include "mastery_evaluator.h"
#include <algorithm>
#include <cmath> // For pow, log
#include <ctime> // For time operations
#include <iomanip> // For fixed and setprecision
#include <iostream>
#include <limits>
#include <map>
#include <sstream> // For stringstream
#include <vector>

using namespace std;

// 基于目标 Rating 和 Sigmoid 曲线的理想时间设定：
// T_ideal = 40 * 2^(K_time * (R_p - R_target) / 400)
const int TARGET_PROBLEM_IDEAL_TIME_MINUTES = 40;
// 缩放系数 K_time: 0.7 (用户指定)
const float TIME_SCALING_FACTOR_K = 0.7f;
const int MIN_IDEAL_TIME_MINUTES = 10;
const int MAX_IDEAL_TIME_MINUTES = 180; // 3小时封顶

// 计划生成默认常量
const int DEFAULT_REVIEW_COUNT = 2; // 默认推荐复习题数
const int DEFAULT_NEW_PROBLEM_COUNT = 3; // 默认推荐新做题数

// 间隔重复参数
const int BASE_REVIEW_INTERVAL_DAYS = 3; // 初始复习间隔天数 (例如 3天)

// --- 权重定义 (45/25/30) ---
const float W1 = 0.45f; // 独立解决度
const float W2 = 0.25f; // 用时惩罚
const float W3 = 0.30f; // 尝试次数惩罚
const float CONSTANT_WEIGHT_SUM = W2 + W3; // 0.55 (E_time=1.0, E_attempts=1.0 的权重和)

// --- 辅助函数：时间处理 ---

// 辅助函数：将 YYYY-MM-DD HH:MM:SS 字符串转换为 time_t
time_t convertToTimeT(const string& dateTimeStr)
{
    if (dateTimeStr.empty())
        return 0;

    tm timeStruct = {};
    // 使用 sscanf 安全解析固定格式
    int year, month, day, hour, min, sec;
    if (sscanf(dateTimeStr.c_str(), "%d-%d-%d %d:%d:%d",
            &year, &month, &day, &hour, &min, &sec)
        != 6) {
        return 0; // 解析失败
    }

    timeStruct.tm_year = year - 1900;
    timeStruct.tm_mon = month - 1;
    timeStruct.tm_mday = day;
    timeStruct.tm_hour = hour;
    timeStruct.tm_min = min;
    timeStruct.tm_sec = sec;
    timeStruct.tm_isdst = -1; // 让 mktime 自行判断 DST

    return mktime(&timeStruct);
}

/**
 * @brief 辅助函数：计算距离给定时间的天数
 * @param dateTimeStr 格式为 "YYYY-MM-DD HH:MM:SS" 的时间字符串
 * @return 距离今天过去的天数
 */
int daysSince(const string& dateTimeStr)
{
    if (dateTimeStr.empty())
        return 10000; // 视为从未解决，给一个很大的天数

    time_t lastSolve = convertToTimeT(dateTimeStr);
    time_t now = time(0);

    if (lastSolve == 0)
        return 10000; // 解析失败，给高天数

    // 计算差值（秒）
    double diffSec = difftime(now, lastSolve);

    // 转换为天数，确保结果非负
    return max(0, (int)floor(diffSec / (60.0 * 60.0 * 24.0)));
}

/**
 * @brief 辅助函数：将天数加到当前日期，返回 YYYY-MM-DD HH:MM:SS 字符串
 * @param daysToAdd 要增加的天数
 * @param baseTime 基础时间（默认为当前时间）
 * @return 计算后的日期时间字符串
 */
string addDaysToDate(int daysToAdd, time_t baseTime = time(0))
{
    // 将天数转换为秒
    long long secondsToAdd = (long long)daysToAdd * 24 * 60 * 60;
    time_t newTime = baseTime + secondsToAdd;

    tm* ltm = localtime(&newTime);
    stringstream ss;
    ss << (1900 + ltm->tm_year) << "-"
       << setfill('0') << setw(2) << (1 + ltm->tm_mon) << "-"
       << setfill('0') << setw(2) << ltm->tm_mday << " "
       << setfill('0') << setw(2) << ltm->tm_hour << ":"
       << setfill('0') << setw(2) << ltm->tm_min << ":"
       << setfill('0') << setw(2) << ltm->tm_sec;
    return ss.str();
}

// --- 核心方法 ---

/**
 * @brief Sigmoid公式：计算用户 Rating R_a 解决题目 Rating R_p 的预期概率。
 * @param problemRating 题目难度 R_p
 * @param userRating 用户能力 R_a
 * @return 预期解决概率 [0, 1]
 */
float MasteryEvaluator::expectedProbability(int problemRating, int userRating)
{
    // ExpectedEV = 1 / (1 + 10^((R_p - R_a) / 400))
    float exponent = (float)(problemRating - userRating) / 400.0f;
    return 1.0f / (1.0f + pow(10.0f, exponent));
}

/**
 * @brief 1. 计算单个题目的 MasteryScore (实际掌握度 A_mastery)，并将其与目标 Rating (R_target) 基准下的期望掌握度 (E_mastery) 进行对比。
 * **新增：计算 NextReviewDate**
 */
void MasteryEvaluator::calculateProblemMastery(Problem& p)
{
    if (p.Difficulty == 0) {
        p.MasteryScore = 0.0f;
        p.NextReviewDate = "";
        return;
    }

    int targetRating = dm.config.TargetCFRating; // R_target

    // ----------------------------------------------------
    // I. 计算实际掌握度 (Actual Mastery: A_mastery)
    // ----------------------------------------------------

    // --- P1: 独立解决度 (45%) ---
    float P1 = p.UsedSolution ? 0.0f : 1.0f; // 1.0 if not UsedSolution

    // --- P2: 用时惩罚 (25%) ---
    float ratingDifference = (float)(p.Difficulty - targetRating);
    float X = ratingDifference / 400.0f;

    // T_ideal 基于 R_target
    float idealTime = TARGET_PROBLEM_IDEAL_TIME_MINUTES * pow(2.0f, TIME_SCALING_FACTOR_K * X);
    idealTime = max((float)MIN_IDEAL_TIME_MINUTES, min((float)MAX_IDEAL_TIME_MINUTES, idealTime));

    float timeRatio = (float)p.TimeSpentMinutes / idealTime;

    float P2;
    if (timeRatio <= 1.0f) {
        P2 = 1.0f; // 100% 效率以内，满分
    } else {
        P2 = 1.0f / timeRatio;
        P2 = max(0.1f, P2);
    }

    // --- P3: 尝试次数惩罚 (30%) ---
    float P3;
    if (p.AttemptCount <= 1) {
        P3 = 1.0f; // 1 次通过，满分
    } else if (p.AttemptCount == 2) {
        P3 = 0.7f; // 2 次通过
    } else {
        P3 = 0.4f; // 3 次及以上通过
    }

    // 实际掌握度 A_mastery (MasteryScore)
    float A_mastery = W1 * P1 + W2 * P2 + W3 * P3;
    A_mastery = max(0.0f, min(1.0f, A_mastery));

    // 设置最终的 MasteryScore
    p.MasteryScore = A_mastery;

    // ----------------------------------------------------
    // II. 计算 NextReviewDate (新增逻辑)
    // ----------------------------------------------------
    if (P1 == 1.0f && A_mastery > 0.0f) { // 仅当独立解决且掌握度大于0时
        // NextInterval = BaseInterval * (1 + A_mastery)
        int reviewDays = (int)round(BASE_REVIEW_INTERVAL_DAYS * (1.0f + A_mastery));
        // 确保间隔至少是 BASE_REVIEW_INTERVAL_DAYS
        reviewDays = max(BASE_REVIEW_INTERVAL_DAYS, reviewDays);

        // 计算 NextReviewDate 基于 DateSolved
        time_t solveTime = convertToTimeT(p.DateSolved);
        if (solveTime != 0) {
            p.NextReviewDate = addDaysToDate(reviewDays, solveTime);
        } else {
            p.NextReviewDate = addDaysToDate(reviewDays); // 基于当前时间
        }

    } else {
        // 如果没有独立解决 (P1=0.0)，则掌握度低，应该尽快复习 (或基于难度有一个很短的间隔)
        // 简单处理：如果没有独立解决，则 NextReviewDate 设为空，依赖 Priority Score 触发快速复习
        p.NextReviewDate = "";
    }

    // ----------------------------------------------------
    // III. 计算期望掌握度 (Expected Mastery: E_mastery)
    // ----------------------------------------------------

    // E_prob: 期望成功概率 (基于目标 Rating: R_target)
    float E_prob_target_benchmark = expectedProbability(p.Difficulty, targetRating);

    // 期望掌握度 E_mastery (E_time=1.0, E_attempts=1.0)
    float E_mastery_benchmark = W1 * E_prob_target_benchmark + CONSTANT_WEIGHT_SUM;
    E_mastery_benchmark = max(0.0f, min(1.0f, E_mastery_benchmark));

    // ----------------------------------------------------
    // IV. 输出比较
    // ----------------------------------------------------

    cout << fixed << setprecision(2);
    cout << "Calculated Problem Mastery for " << p.ProblemID
         << " (Diff: " << p.Difficulty << ", Target R: " << targetRating << "):\n";
    cout << "  - Expected Mastery (E_mastery) : " << E_mastery_benchmark << " (基于 Target R=" << targetRating << " 的期望 E_prob=" << E_prob_target_benchmark << ")\n";
    cout << "  - Actual Mastery (A_mastery)   : " << A_mastery << " (P1:" << P1 << ", P2:" << P2 << ", P3:" << P3 << ")\n";
    cout << "  - Next Review Date             : " << (p.NextReviewDate.empty() ? "N/A (未独立解决)" : p.NextReviewDate) << "\n"; // 输出 NextReviewDate

    if (A_mastery >= E_mastery_benchmark) {
        cout << "  => Result: 超越目标预期 (" << (A_mastery - E_mastery_benchmark) << ")\n";
    } else {
        cout << "  => Result: 低于目标预期 (" << (A_mastery - E_mastery_benchmark) << ")\n";
    }
}

/**
 * @brief 2. 计算整体平均掌握度，并计算整体平均预期掌握度进行对比。
 */
void MasteryEvaluator::calculateOverallRating()
{
    float totalActualMastery = 0.0f; // 实际掌握度总和
    float totalExpectedMastery = 0.0f; // 预期掌握度总和 (基于 TargetCFRating)
    int problemCount = 0;

    int targetRating = dm.config.TargetCFRating; // R_target

    for (const auto& pair : dm.problems) {
        const Problem& p = pair.second;
        // 仅计算 MasteryScore > 0.0 的题目
        if (p.MasteryScore > 0.0f) {
            totalActualMastery += p.MasteryScore;
            problemCount++;

            // 计算该题在 TargetCFRating 下的预期掌握度 (E_mastery)
            float E_prob_target_benchmark = expectedProbability(p.Difficulty, targetRating);
            // 预期掌握度 E_mastery (假设用时和尝试次数满分)
            float E_mastery_benchmark = W1 * E_prob_target_benchmark + CONSTANT_WEIGHT_SUM;
            E_mastery_benchmark = max(0.0f, min(1.0f, E_mastery_benchmark));

            totalExpectedMastery += E_mastery_benchmark;
        }
    }

    cout << "--- Overall Mastery Evaluation ---\n";
    if (problemCount == 0) {
        cout << "No valid problem data to calculate overall mastery." << endl;
        dm.config.OverallMasteryScore = 0.0f;
        dm.config.CurrentCFEquivalent = 1500; // 默认值
        return;
    }

    // 计算平均值
    float avgActualMastery = totalActualMastery / problemCount;
    float avgExpectedMastery = totalExpectedMastery / problemCount;

    dm.config.OverallMasteryScore = avgActualMastery; // 存储实际平均掌握度

    // 输出对比结果
    cout << fixed << setprecision(2);
    cout << "  - Target CF Rating             : " << targetRating << endl;
    cout << "  - Total Problems Count         : " << problemCount << endl;
    cout << "  - **Actual Avg Mastery** : " << avgActualMastery << endl;
    cout << "  - **Expected Avg Mastery** : " << avgExpectedMastery << " (基于 Target R=" << targetRating << ")\n";

    float difference = avgActualMastery - avgExpectedMastery;
    if (difference >= 0.0f) {
        cout << "  => **Conclusion**: 超越目标预期 (" << difference << ")。您的学习效率达到了目标Rating的要求。\n";
    } else {
        cout << "  => **Conclusion**: 低于目标预期 (" << difference << ")。您的学习效率仍需提高，尤其在用时和独立解决方面。\n";
    }

    // 更新CurrentCFEquivalent为整体掌握度（Avg Mastery * 1000）
    dm.config.CurrentCFEquivalent = static_cast<int>(round(avgActualMastery * 1000.0f));
}

/**
 * @brief 3. 计算每个算法专题的平均掌握度 (Mastery Index)，并与预期掌握度进行对比。
 */
void MasteryEvaluator::calculateTopicRatings()
{
    // 采纳建议：获取整体掌握度作为样本不足时的默认值
    int overallMasteryIndex = dm.config.CurrentCFEquivalent;
    int targetRating = dm.config.TargetCFRating; // R_target

    cout << "\n--- Topic Mastery Evaluation ---\n";
    cout << "Starting topic mastery index calculation (Target Rating: " << targetRating << ")...\n";
    cout << fixed << setprecision(2);

    for (auto& topicPair : dm.topics) {
        string topicName = topicPair.first;
        Topic& t = topicPair.second;

        float totalActualMastery = 0.0f;
        float totalExpectedMastery = 0.0f; // 新增：预期掌握度总和
        int problemCount = 0;

        for (const auto& problemPair : dm.problems) {
            const Problem& p = problemPair.second;
            if (p.MasteryScore > 0.0f) {
                // 检查题目是否包含当前专题
                if (find(p.Topics.begin(), p.Topics.end(), topicName) != p.Topics.end()) {
                    totalActualMastery += p.MasteryScore;
                    problemCount++;

                    // 计算该题在 TargetCFRating 下的预期掌握度 (E_mastery)
                    float E_prob_target_benchmark = expectedProbability(p.Difficulty, targetRating);
                    // 预期掌握度 E_mastery (假设用时和尝试次数满分)
                    float E_mastery_benchmark = W1 * E_prob_target_benchmark + CONSTANT_WEIGHT_SUM;
                    E_mastery_benchmark = max(0.0f, min(1.0f, E_mastery_benchmark));

                    totalExpectedMastery += E_mastery_benchmark;
                }
            }
        }

        if (problemCount < 3) {
            // 样本不足时，使用整体平均掌握度作为默认值
            t.TopicCFRating = overallMasteryIndex;
            cout << "Topic [" << topicName << "]: 样本不足(" << problemCount << "题)。使用整体平均掌握度指数: " << overallMasteryIndex << "\n";
            continue;
        }

        float avgActualMastery = totalActualMastery / problemCount;
        float avgExpectedMastery = totalExpectedMastery / problemCount;

        // 将平均掌握度 (0.0 - 1.0) 存储为整数 (0 - 1000)
        t.TopicCFRating = static_cast<int>(round(avgActualMastery * 1000.0f));

        cout << "\nTopic [" << topicName << "] (" << problemCount << "题):\n";
        cout << "  - **实际平均掌握度** : " << avgActualMastery << "\n";
        cout << "  - **预期平均掌握度** : " << avgExpectedMastery << " (基于 Target R=" << targetRating << ")\n";

        float difference = avgActualMastery - avgExpectedMastery;
        if (difference >= 0.0f) {
            cout << "  => **结论**: 超越目标预期 (" << difference << ")。该专题表现优秀。\n";
        } else {
            cout << "  => **结论**: 低于目标预期 (" << difference << ")。**这是短板！**需要重点提高。\n";
        }
    }

    cout << "All topic mastery indexes updated.\n";
}

/**
 * @brief 4. 生成学习计划 (基于复习优先级和短板原则)
 */
void MasteryEvaluator::generateStudyPlan()
{
    // 确保数据是最新的
    calculateOverallRating();
    calculateTopicRatings();

    cout << "\n--- 学习计划 ---\n";
    cout << fixed << setprecision(2);
    cout << "当前整体平均掌握度: " << dm.config.OverallMasteryScore << endl;

    if (dm.problems.empty()) {
        cout << "没有已解决的题目记录，请先使用 'log add' 命令添加。\n";
        return;
    }

    // --- 1. 复习推荐 (Review Problem Recommendation) ---
    cout << "\n[复习推荐]（基于遗忘和低掌握度）：\n";

    // 存储需要复习的题目及其优先级
    struct ReviewCandidate {
        float priorityScore;
        string id;
        int daysSinceSolve;
        float mastery;
        int difficulty;
        string title;
        bool isDue; // 新增：是否已过 NextReviewDate
    };

    vector<ReviewCandidate> candidates;

    // 获取当前时间 time_t
    time_t now = time(0);

    for (auto& pair : dm.problems) {
        Problem& p = pair.second;
        if (p.MasteryScore > 0.0f) {

            int days = daysSince(p.DateSolved); // 计算天数

            // 核心公式: Priority Score = (1 / MasteryScore) * log_e(DaysSinceLastSolve + 1) * (Difficulty / 1000)
            float score = (1.0f / max(0.1f, p.MasteryScore)) * log(days + 1.0f) * ((float)p.Difficulty / 1000.0f);

            bool isDueNow = false;
            // 判断是否已过 NextReviewDate
            if (!p.NextReviewDate.empty()) {
                time_t nextReviewTime = convertToTimeT(p.NextReviewDate);
                if (nextReviewTime != 0 && difftime(nextReviewTime, now) <= 0) {
                    isDueNow = true;
                }
            } else if (p.UsedSolution) {
                // 如果是看了题解，没有 NextReviewDate，但 MasteryScore>0，也应该快速复习（Score会很高）
                isDueNow = true;
            }

            // 仅当 isDueNow 为真或 Priority Score 足够高时才考虑加入候选
            if (isDueNow || score > 0.5f) {
                candidates.push_back({ score, p.ProblemID, days, p.MasteryScore, p.Difficulty, p.Title, isDueNow });
            }
        }
    }

    // 排序：首先按 isDueNow 降序（到期优先），然后按 Priority Score 降序
    sort(candidates.begin(), candidates.end(), [](const ReviewCandidate& a, const ReviewCandidate& b) {
        if (a.isDue != b.isDue) {
            return a.isDue; // isDue=true 的优先
        }
        return a.priorityScore > b.priorityScore;
    });

    int reviewCount = 0;

    // 输出排名前 DEFAULT_REVIEW_COUNT 的题目
    for (const auto& item : candidates) {
        if (reviewCount >= DEFAULT_REVIEW_COUNT)
            break;

        // 标记是否已到期
        string dueStatus = item.isDue ? " [🚨已到期]" : "";

        cout << fixed << setprecision(2);
        cout << reviewCount + 1 << ". [" << item.id << "] " << item.title << dueStatus
             << " (Mastery: " << item.mastery
             << ", Days Ago: " << item.daysSinceSolve
             << ", Score: " << item.priorityScore << ")\n";
        reviewCount++;
    }

    if (reviewCount == 0) {
        cout << "  - 恭喜！目前没有需要紧急复习的题目。\n";
    }

    // --- 2. 新题推荐 (New Problem Focus) ---
    cout << "\n[新题推荐]（共 " << DEFAULT_NEW_PROBLEM_COUNT << " 题）:\n";

    // 2.1. 确定学习焦点 (Weakest Topic based on stored TopicCFRating/Mastery Index)
    int overallMasteryIndex = dm.config.CurrentCFEquivalent; // Avg Mastery * 1000

    string weakestTopic = "N/A";
    int minMasteryIndex = 1001;
    int topicCount = 0;

    // 找到专项 Mastery Index 最低的专题 (现在默认值是 overallMasteryIndex)
    for (const auto& pair : dm.topics) {
        topicCount++;
        // 排除默认值 (overallMasteryIndex)，除非所有专题都是这个值
        if (pair.second.TopicCFRating > 0 && pair.second.TopicCFRating <= minMasteryIndex) {
            if (pair.second.TopicCFRating < overallMasteryIndex || topicCount == dm.topics.size()) {
                minMasteryIndex = pair.second.TopicCFRating;
                weakestTopic = pair.first;
            }
        }
    }

    // 2.2. 根据整体掌握度确定推荐难度
    int assumedEquivalentRating = dm.config.TargetCFRating;

    // 难度范围建议：[Assumed Equivalent Rating + 100, Assumed Equivalent Rating + 300]
    int lowerBound = assumedEquivalentRating + 100;
    int upperBound = assumedEquivalentRating + 300;
    lowerBound = max(1200, lowerBound); // 确保难度不低于 1200

    string strategyTitle;

    if (weakestTopic == "N/A" || minMasteryIndex >= 850 || minMasteryIndex == overallMasteryIndex) { // 掌握度普遍较高或没有有效数据 (即都是默认值)
        strategyTitle = "🚀 全面提升";
        cout << "  - **策略：** 您的掌握度普遍较高或专题数据不足。建议平均训练，重点攻克难度 ["
             << lowerBound << " - " << upperBound << "] 的题目。\n";
    } else {
        float weakestAvgMastery = minMasteryIndex / 1000.0f;
        strategyTitle = "🚧 短板突破";
        cout << fixed << setprecision(2);
        cout << "  - **最弱项：** " << weakestTopic << " (Avg Mastery: " << weakestAvgMastery << ")\n";
        cout << "  - **策略：** 集中精力在 [" << weakestTopic << "] 专题上，推荐难度区间 ["
             << lowerBound << " - " << upperBound << "] 的题目。\n";
        cout << "  - **分配：** 建议将 " << DEFAULT_NEW_PROBLEM_COUNT / 2 + (DEFAULT_NEW_PROBLEM_COUNT % 2)
             << " 题分配给 " << weakestTopic << "，剩余 "
             << DEFAULT_NEW_PROBLEM_COUNT / 2 << " 题用于综合训练。\n";
    }
}